#pragma once


#include <typeinfo>
#include <stdexcept>
#include <memory>
#include <type_traits>
#include "utility.hpp"
#include "scope.hpp"
#include "memory_resource.hpp"
#include "none.hpp"
#include "config/config_begin.h"

namespace cpp{
	namespace __any
	{
		template<class T>
		struct _AddConst
		{
			using type = T;
		};

		template<class T>
		struct _AddConst<T&>
		{
			using type = T const &;
		};

		template<class T>
		struct _AddConst<T&&>
		{
			using type = T const &&;
		};

		template<size_t Size = sizeof(void*) * 4>
		struct StorageTrait
		{
			using  _StorageType = std::aligned_union<Size, std::max_align_t>;

			using storage_t = typename _StorageType::type;

			template<class T,
				size_t AlignFactor = _StorageType::alignment_value / alignof(T),
				class = std::enable_if_t< (sizeof(T) <= sizeof(storage_t)) && ((AlignFactor != 0) && !(AlignFactor & (AlignFactor - 1))) >,
				class = std::enable_if_t< std::is_nothrow_move_constructible<T>::value >
			>
				static  std::true_type test(int);

			template<class T>
			static std::false_type test(...);

			template<class T>
			using can_fit = decltype(test<T>(0));
		};

		template<class T, class StorageT = StorageTrait<>, class = void>
		struct FitTrait : StorageT::template can_fit<T>
		{

		};
	}

	class bad_any_cast :public std::bad_cast
	{
	public:
		virtual const char * what() const{ return "bad_any_cast: failed conversion using any_cast"; }
	};

	class any final
	{
		using  StorageTrait = __any::StorageTrait<>;
		using  storage_t = typename StorageTrait::storage_t;

		template<class T>
		using can_fit = __any::FitTrait<T, StorageTrait>;

		union Storage
		{
			void*						_dynamic = nullptr;
			storage_t					_stack;
		}_storage;

		struct vtable
		{
			const std::type_info&	(*_type)()	noexcept;
			void(*_delete)(Storage &)			noexcept;
			void(*_copy)(const Storage &, Storage &);
			void(*_move)(Storage &, Storage &)	noexcept;

		}  *pvtable = nullptr;


		template<class T, class = void >
		struct stack_vtable
		{
			static const std::type_info& type() noexcept
			{
				return typeid(T);
			}
			static void copy(const Storage & src, Storage & storage)
			{
				::new (static_cast<void*>(&storage._stack)) T(reinterpret_cast<const T&>(src._stack));
			}

			static void move(Storage &src, Storage & storage) noexcept
			{
				::new (static_cast<void*>(&storage._stack)) T(std::move(reinterpret_cast<T &>(src._stack)));
				_delete(src);
			}

			template<class T>
			static inline void _Destory(T*p){ p->~T(); }

			static void _delete(Storage & storage) noexcept
			{
				_Destory(reinterpret_cast<T*>(&storage._stack));
			}

			template<class...Args>
			static void create(Storage & storage, Args&&...args)
			{
				::new (static_cast<void*>(&storage._stack))  T(std::forward<Args>(args)...);
			}

			static vtable* get_vtable()
			{
				static vtable _vtable = {
					type,
					_delete,
					copy,
					move,
				};
				return &_vtable;
			}
		};


		template<class T, class = void>
		struct dynamic_vtable
		{
			static const std::type_info& type() noexcept
			{
				return typeid(T);
			}
			static void copy(const Storage & src, Storage & storage)
			{
				storage._dynamic = new T(*static_cast<const T *>(src._dynamic));
			}

			static void move(Storage & src, Storage & storage) noexcept
			{
				storage._dynamic = src._dynamic;
				src._dynamic = nullptr;
			}

			static void _delete(Storage & storage) noexcept
			{
				delete static_cast<T*>(storage._dynamic);
			}

			template<class...Args>
			static void create(Storage & storage, Args&&...args)
			{
				storage._dynamic = new T(std::forward<Args>(args)...);
			}
			static vtable* get_vtable()
			{
				static vtable _vtable = {
					type,
					_delete,
					copy,
					move,
				};
				return &_vtable;
			}
		};

		template<class T>
		using VTable = std::conditional_t< can_fit<T>::value, stack_vtable<T>, dynamic_vtable<T> >;

	public:
		constexpr any() noexcept {}
		constexpr any(none_t) noexcept {}

		any(const any& other)
			:pvtable(other.pvtable)
		{
			if(other.has_value())
			{
				other.pvtable->_copy(other._storage, _storage);
			}
		}

		any(any&& other) noexcept
			:pvtable(other.pvtable)
		{
			if(other.has_value())
			{
				other.pvtable->_move(other._storage, _storage);
				other.pvtable = nullptr;
			}
		}

		template<typename T, typename = std::enable_if_t<!std::is_same< std::decay_t<T>, any >::value> >
		any(T&& value)
			:pvtable(VTable<std::decay_t<T>>::get_vtable())
		{
			VTable<std::decay_t<T>>::create(_storage, std::forward<T>(value));
		}

		template<typename T, class... Args, typename = std::enable_if_t<!std::is_same< std::decay_t<T>, any >::value> >
		explicit any(::cpp::in_place_type_t<T>, Args&&... args)
			:pvtable(VTable<T>::get_vtable())
		{
			VTable<T>::create(_storage, std::forward<Args>(args)...);
		}

		template<typename T, class U, class... Args,
			typename = std::enable_if_t<!std::is_same< std::decay_t<T>, any >::value>,
			typename = std::enable_if_t < std::is_constructible<T, std::initializer_list<U>&, Args&&...>::value > >
			explicit any(::cpp::in_place_type_t<T>, std::initializer_list<U> ilist, Args&&... args)
			:pvtable(VTable<T>::get_vtable())
		{
			VTable<T>::create(_storage, ilist, std::forward<Args>(args)...);
		}

		~any()
		{
			reset();
		}

		any& operator=(none_t) noexcept
		{
			reset();
			return *this;
		}

		any& operator=(const any& rhs)
		{
			if(this == &rhs)
			{
				return *this;
			}
			any(rhs).swap(*this);
			return *this;
		}
		any& operator=(any&& rhs)
		{
			if(this == &rhs)
			{
				return *this;
			}
			any(std::move(rhs)).swap(*this);
			return *this;
		}

		template<typename ValueType, typename = std::enable_if_t<!std::is_same< std::decay_t<ValueType>, any >::value>>
		any& operator=(ValueType&& rhs)
		{
			any(std::forward<ValueType>(rhs)).swap(*this);
			return *this;
		}


		void swap(any& other) noexcept
		{
			if(!has_value() && !other.has_value())
				return;

			if(has_value() && other.has_value())
			{
				if(this == &other)
				{
					return;
				}

				any tmp;
				tmp.pvtable = pvtable;
				pvtable->_move(_storage, tmp._storage);
				//pvtable->_delete(_storage);

				pvtable = other.pvtable;
				pvtable->_move(other._storage, _storage);
				//other.pvtable->_delete(other._storage);

				other.pvtable = tmp.pvtable;
				other.pvtable->_move(tmp._storage, other._storage);
				//tmp.pvtable->_delete(tmp._storage);
				tmp.pvtable = nullptr;
			}
			else
			{
				any* hasValue = has_value() ? this : &other;
				any* noValue = !has_value() ? this : &other;

				noValue->pvtable = hasValue->pvtable;
				hasValue->pvtable->_move(hasValue->_storage, noValue->_storage);
				//hasValue->pvtable->_delete(hasValue->_storage);
				hasValue->pvtable = nullptr;
			}
		}

		void reset() noexcept
		{
			if(pvtable)
			{
				pvtable->_delete(_storage);
				pvtable = nullptr;
			}
		}

		bool has_value() const noexcept
		{
			return !!pvtable;
		}

		const type_info& type() const
		{
			return pvtable ? pvtable->_type() : typeid(void);
		}

		template<typename T>
		void assign(T&& value)
		{
			reset();
			VTable<std::decay_t<T>>::create(_storage, std::forward<T>(value));
			pvtable = VTable<std::decay_t<T>>::get_vtable();
		}

		template<typename ValueType, class... Args>
		void emplace(Args&&... args)
		{
			reset();
			VTable<ValueType>::create(_storage, std::forward<Args>(args)...);
			pvtable = VTable<ValueType>::get_vtable();
		}

		template<typename ValueType, class U, class... Args>
		void emplace(std::initializer_list<U> ilist, Args&&... args)
		{
			reset();
			VTable<ValueType>::create(_storage, ilist, std::forward<Args>(args)...);
			pvtable = VTable<ValueType>::get_vtable();
		}


		/**
		*
		**/
		template<class T>
		T value()
		{
			using unref = std::remove_reference_t < T >;

			using ref = std::conditional_t < std::is_reference<T>::value, T, std::add_lvalue_reference_t<unref> >;

			auto pv = target<unref>();
			if(!pv)
			{
				throw bad_any_cast();
			}

			return  static_cast<ref>(*pv);
		}

		template<class T>
		typename __any::_AddConst<T>::type  value() const
		{
			using unref = std::remove_reference_t < T >;

			using ref = std::conditional_t < std::is_reference<T>::value,
				typename __any::_AddConst<T>::type,
				std::add_lvalue_reference_t<const unref> >;

			auto pv = target<unref>();
			if(!pv)
			{
				throw bad_any_cast();
			}

			return  static_cast<ref>(*pv);
		}

	private:
		template< class T >
		T* target()
		{
			if(pvtable && pvtable->_type() == typeid(T))
			{
				if(can_fit< std::remove_cv_t< T > >::value)
				{
					return std::addressof(reinterpret_cast<T&>(_storage._stack));
				}
				else
				{
					return std::addressof(*static_cast<T*>(_storage._dynamic));
				}
			}
			return nullptr;
		}

		template< class T >
		const T* target() const
		{
			if(pvtable && pvtable->_type() == typeid(T))
			{
				if(can_fit< std::remove_cv_t< T > >::value)
				{
					return std::addressof(reinterpret_cast<const T&>(_storage._stack));
				}
				else
				{
					return std::addressof(*static_cast<const T*>(_storage._dynamic));
				}
			}
			return nullptr;
		}

		template<class ValueType>
		friend	const ValueType* any_cast(const any* operand);

		template<class ValueType>
		friend ValueType* any_cast(any* operand);
	};


	inline void swap(any& lhs, any& rhs) noexcept
	{
		lhs.swap(rhs);
	}

	template<int..., class T>
	any make_any(T&& value)
	{
		return{ std::forward<T>(value) };
	}

	template <class T, class ...Args>
	any make_any(Args&& ...args)
	{
		return any{ in_place<T>, std::forward<Args>(args)... };
	}

	template <class T, class U, class ...Args>
	any make_any(std::initializer_list<U> il, Args&& ...args)
	{
		return any{ in_place<T>, il, std::forward<Args>(args)... };
	}

	template<class ValueType>
	ValueType* any_cast(any* operand)
	{
		return  operand ? operand->target<ValueType>() : nullptr;
	}

	template<class ValueType>
	const ValueType* any_cast(const any* operand)
	{
		return  operand ? operand->target<ValueType>() : nullptr;
	}


	template<class ValueType>
	typename __any::_AddConst<ValueType>::type any_cast(const any& operand)
	{
		using unref = std::remove_reference_t < ValueType >;

		using ref = std::conditional_t < std::is_reference<ValueType>::value,
			typename __any::_AddConst<ValueType>::type,
			std::add_lvalue_reference_t<const unref> >;

		auto pv = any_cast<unref>(&operand);
		if(!pv)
		{
			throw bad_any_cast();
		}

		return static_cast<ref>(*pv);
	}

	template<class ValueType>
	ValueType any_cast(any& operand)
	{
		using unref = std::remove_reference_t < ValueType >;

		using ref = std::conditional_t < std::is_reference<ValueType>::value, ValueType, std::add_lvalue_reference_t<unref> >;

		auto pv = any_cast<unref>(&operand);
		if(!pv)
		{
			throw bad_any_cast();
		}

		return  static_cast<ref>(*pv);
	}

	template<class ValueType, class = std::enable_if_t< std::is_rvalue_reference<ValueType&&>::value || std::is_const< std::remove_reference_t< ValueType > >::value  > >
	ValueType any_cast(any&& operand)
	{
		return any_cast<ValueType&&>(operand);
	}


	template <>
	struct nullable_traits<any> {
		static constexpr none_t none() { return none_t{}; }
	};
}




namespace cpp{

	class unique_any final
	{
		using  StorageTrait = __any::StorageTrait<>;
		using  storage_t = typename StorageTrait::storage_t;
		template<class T>
		using can_fit = __any::FitTrait<T, StorageTrait>;

		union Storage
		{
			void*						_dynamic = nullptr;
			storage_t					_stack;
		}_storage;

		struct vtable
		{
			const std::type_info&	(*_type)() noexcept;
			void(*_delete)(Storage &)noexcept;
			void(*_move)(Storage &, Storage &) noexcept;

		}  *pvtable = nullptr;

		template<class T>
		struct stack_vtable
		{
			static const std::type_info& type() noexcept
			{
				return typeid(T);
			}

			static void move(Storage &src, Storage & storage) noexcept
			{
				::new  (static_cast<void*>(&storage._stack)) T(std::move(reinterpret_cast<T&>(src._stack)));
				_delete(src);
			}

			template<class T>
			static inline void _Destory(T*p){ p->~T(); }

			static void _delete(Storage & storage) noexcept
			{
				_Destory(reinterpret_cast<T *>(&storage._stack));
			}

			template<class...Args>
			static void create(Storage & storage, Args&&...args)
			{
				::new (static_cast<void*>(&storage._stack))  T(std::forward<Args>(args)...);
			}

			static vtable* get_vtable()
			{
				static vtable _vtable = {
					type,
					_delete,
					move,
				};
				return &_vtable;
			}
		};

		template<class T>
		struct dynamic_vtable
		{
			static const std::type_info& type() noexcept
			{
				return typeid(T);
			}

			static void move(Storage & src, Storage & storage) noexcept
			{
				storage._dynamic = src._dynamic;
				src._dynamic = nullptr;
			}

			static void _delete(Storage & storage) noexcept
			{
				delete static_cast<T*>(storage._dynamic);
			}

			template<class...Args>
			static void create(Storage & storage, Args&&...args)
			{
				storage._dynamic = new T(std::forward<Args>(args)...);
			}

			static vtable* get_vtable()
			{
				static vtable _vtable = {
					type,
					_delete,
					move,
				};
				return &_vtable;
			}
		};

		template<class T>
		using VTable = std::conditional_t< can_fit<T>::value, stack_vtable<T>, dynamic_vtable<T> >;

	public:
		constexpr unique_any() noexcept {}
		constexpr unique_any(none_t) noexcept {}

		unique_any(const unique_any&) = delete;

		unique_any(unique_any&& other) noexcept
			:pvtable(other.pvtable)
		{
			if(other.has_value())
			{
				other.pvtable->_move(other._storage, _storage);
				other.pvtable = nullptr;
			}
		}

		template<typename T, typename = std::enable_if_t<!std::is_same< std::decay_t<T>, unique_any >::value> >
		unique_any(T&& value)
			:pvtable(VTable<std::decay_t<T>>::get_vtable())
		{
			VTable<std::decay_t<T>>::create(_storage, std::forward<T>(value));
		}

		template<typename T, class... Args, typename = std::enable_if_t<!std::is_same< std::decay_t<T>, unique_any >::value> >
		explicit unique_any(::cpp::in_place_type_t<T>, Args&&... args)
			:pvtable(VTable<T>::get_vtable())
		{
			static_assert(!std::is_reference<T>::value, "");
			VTable<T>::create(_storage, std::forward<Args>(args)...);
		}

		template<typename T, class U, class... Args,
			typename = std::enable_if_t<!std::is_same< std::decay_t<T>, unique_any >::value>,
			typename = std::enable_if_t < std::is_constructible<T, std::initializer_list<U>&, Args&&...>::value >>
			explicit unique_any(::cpp::in_place_type_t<T>, std::initializer_list<U> ilist, Args&&... args)
			:pvtable(VTable<T>::get_vtable())
		{
			static_assert(!std::is_reference<T>::value, "");
			VTable<T>::create(_storage, ilist, std::forward<Args>(args)...);
		}

		~unique_any()
		{
			reset();
		}

		unique_any& operator=(none_t) noexcept
		{
			reset();
			return *this;
		}

		unique_any& operator=(const unique_any& rhs) = delete;

		unique_any& operator=(unique_any&& rhs)
		{
			if(this == &rhs)
			{
				return *this;
			}
			unique_any(std::move(rhs)).swap(*this);
			return *this;
		}

		template<typename ValueType, typename = std::enable_if_t<!std::is_same< std::decay_t<ValueType>, unique_any >::value>>
		unique_any& operator=(ValueType&& rhs)
		{
			unique_any(std::forward<ValueType>(rhs)).swap(*this);
			return *this;
		}


		void swap(unique_any& other) noexcept
		{
			if(!has_value() && !other.has_value())
				return;

			if(has_value() && other.has_value())
			{
				if(this == &other)
				{
					return;
				}

				unique_any tmp;
				tmp.pvtable = pvtable;
				pvtable->_move(_storage, tmp._storage);
				//pvtable->_delete(_storage);

				pvtable = other.pvtable;
				pvtable->_move(other._storage, _storage);
				//other.pvtable->_delete(other._storage);

				other.pvtable = tmp.pvtable;
				other.pvtable->_move(tmp._storage, other._storage);
				//tmp.pvtable->_delete(tmp._storage);
				tmp.pvtable = nullptr;
			}
			else
			{
				unique_any* hasValue = has_value() ? this : &other;
				unique_any* noValue = !has_value() ? this : &other;

				noValue->pvtable = hasValue->pvtable;
				hasValue->pvtable->_move(hasValue->_storage, noValue->_storage);
				//hasValue->pvtable->_delete(hasValue->_storage);
				hasValue->pvtable = nullptr;
			}
		}

		void reset() noexcept
		{
			if(pvtable)
			{
				pvtable->_delete(_storage);
				pvtable = nullptr;
			}
		}

		bool has_value() const noexcept
		{
			return !!pvtable;
		}

		const type_info& type() const
		{
			return pvtable ? pvtable->_type() : typeid(void);
		}

		template<typename ValueType>
		void assign(ValueType&& value)
		{
			reset();
			VTable<std::decay_t<ValueType>>::create(_storage, std::forward<ValueType>(value));
			pvtable = VTable<std::decay_t<ValueType>>::get_vtable();
		}


		template<typename ValueType, class... Args>
		void emplace(Args&&... args)
		{
			reset();
			VTable<ValueType>::create(_storage, std::forward<Args>(args)...);
			pvtable = VTable<ValueType>::get_vtable();
		}

		template<typename ValueType, class U, class... Args>
		void emplace(std::initializer_list<U> ilist, Args&&... args)
		{
			reset();
			VTable<ValueType>::create(_storage, ilist, std::forward<Args>(args)...);
			pvtable = VTable<ValueType>::get_vtable();
		}


		/**
		*
		**/
		template<class T>
		T value()
		{
			using unref = std::remove_reference_t < T >;

			using ref = std::conditional_t < std::is_reference<T>::value, T, std::add_lvalue_reference_t<unref> >;

			auto pv = target<unref>();
			if(!pv)
			{
				throw bad_any_cast();
			}

			return  static_cast<ref>(*pv);
		}

		template<class T>
		typename __any::_AddConst<T>::type  value() const
		{
			using unref = std::remove_reference_t < T >;

			using ref = std::conditional_t < std::is_reference<T>::value,
				typename __any::_AddConst<T>::type,
				std::add_lvalue_reference_t<const unref> >;

			auto pv = target<unref>();
			if(!pv)
			{
				throw bad_any_cast();
			}

			return  static_cast<ref>(*pv);
		}

	private:
		template< class T >
		T* target()
		{
			if(pvtable && pvtable->_type() == typeid(T))
			{
				if(can_fit< std::remove_cv_t< T > >::value)
				{
					return std::addressof(reinterpret_cast<T&>(_storage._stack));
				}
				else
				{
					return std::addressof(*static_cast<T*>(_storage._dynamic));
				}
			}
			return nullptr;
		}

		template< class T >
		const T* target() const
		{
			if(pvtable && pvtable->_type() == typeid(T))
			{
				if(can_fit< std::remove_cv_t< T > >::value)
				{
					return std::addressof(reinterpret_cast<const T&>(_storage._stack));
				}
				else
				{
					return std::addressof(*static_cast<const T*>(_storage._dynamic));
				}
			}
			return nullptr;
		}

		template<class ValueType>
		friend	const ValueType* any_cast(const unique_any* operand);

		template<class ValueType>
		friend ValueType* any_cast(unique_any* operand);
	};

	inline void swap(unique_any& lhs, unique_any& rhs) noexcept
	{
		lhs.swap(rhs);
	}

	template<int..., class T>
	unique_any make_unique_any(T&& value)
	{
		return{ std::forward<T>(value) };
	}

	template <class T, class ...Args>
	unique_any make_unique_any(Args&& ...args)
	{
		return unique_any{ in_place<T>, std::forward<Args>(args)... };
	}

	template <class T, class U, class ...Args>
	unique_any make_unique_any(std::initializer_list<U> il, Args&& ...args)
	{
		return unique_any{ in_place<T>, il, std::forward<Args>(args)... };
	}


	template<class ValueType>
	ValueType* any_cast(unique_any* operand)
	{
		return  operand ? operand->target<ValueType>() : nullptr;
	}

	template<class ValueType>
	const ValueType* any_cast(const unique_any* operand)
	{
		return  operand ? operand->target<ValueType>() : nullptr;
	}


	template<class ValueType>
	typename __any::_AddConst<ValueType>::type any_cast(const unique_any& operand)
	{
		using unref = std::remove_reference_t < ValueType >;

		using ref = std::conditional_t < std::is_reference<ValueType>::value,
			typename __any::_AddConst<ValueType>::type,
			std::add_lvalue_reference_t<const unref> >;

		auto pv = any_cast<unref>(&operand);
		if(!pv)
		{
			throw bad_any_cast();
		}

		return static_cast<ref>(*pv);
	}

	template<class ValueType>
	ValueType any_cast(unique_any& operand)
	{
		using unref = std::remove_reference_t < ValueType >;

		using ref = std::conditional_t < std::is_reference<ValueType>::value, ValueType, std::add_lvalue_reference_t<unref> >;

		auto pv = any_cast<unref>(&operand);
		if(!pv)
		{
			throw bad_any_cast();
		}

		return  static_cast<ref>(*pv);
	}

	template<class ValueType, class = std::enable_if_t< std::is_rvalue_reference<ValueType&&>::value || std::is_const< std::remove_reference_t< ValueType > >::value  > >
	ValueType any_cast(unique_any&& operand)
	{
		return any_cast<ValueType&&>(operand);
	}


	template <>
	struct nullable_traits<unique_any> {
		static constexpr none_t none() { return none_t{}; }
	};
}



#if 1

namespace cpp
{
	namespace pmr
	{
		class any final
		{
			using  StorageTrait = __any::StorageTrait<>;
			using  storage_t = typename StorageTrait::storage_t;
			template<class T>
			using can_fit = __any::FitTrait<T, StorageTrait>;

			struct Data;

			struct vtable
			{
				const std::type_info&	(*_type)()	noexcept;
				void(*_delete)(Data &)			noexcept;

				void(*_copy)(const Data &, Data &);
				void(*_copy_use_resource)(const Data &, Data &);

				void(*_move)(Data &, Data &)	noexcept;
				void(*_move_use_resource)(Data &, Data &)	noexcept;

			}  *pvtable = nullptr;

			struct Data
			{
				memory_resource*				_resource;
				union
				{
					void*						_dynamic = nullptr;
					storage_t					_stack;
				};

				Data() :_resource(get_default_resource()){	}

				Data(cpp::pmr::memory_resource* resource) :_resource(resource){}
			}	_data;

			template<class T>
			struct stack_vtable
			{
				static const std::type_info& type() noexcept
				{
					return typeid(T);
				}

				static void copy(const Data & from, Data & to)
				{
					to._resource = from._resource;
					polymorphic_allocator<> alloc{ to._resource };

					alloc.construct(reinterpret_cast<T*>(&to._stack), reinterpret_cast<const T&>(from._stack));
				}

				static void copy_use_resource(const Data & from, Data & to)
				{
					polymorphic_allocator<> alloc{ to._resource };
					alloc.construct(reinterpret_cast<T*>(&to._stack), reinterpret_cast<const T &>(from._stack));
				}

				static void move(Data &from, Data & to) noexcept
				{
					to._resource = from._resource;
					polymorphic_allocator<> alloc{ to._resource };

					alloc.construct(reinterpret_cast<T*>(&to._stack), std::move(reinterpret_cast<T&>(from._stack)));

					_delete(from);
				}

				static void move_use_resource(Data &from, Data & to) noexcept
				{
					polymorphic_allocator<> alloc{ to._resource };

					alloc.construct(reinterpret_cast<T*>(&to._stack), std::move(reinterpret_cast<T&>(from._stack)));
					_delete(from);
				}

				static void _delete(Data & data) noexcept
				{
					polymorphic_allocator<> alloc{ data._resource };
					alloc.destroy(reinterpret_cast<T*>(&data._stack));
				}

				template<class...Args>
				static void create(Data & data, Args&&...args)
				{
					pmr::polymorphic_allocator<> alloc(data._resource);
					alloc.construct(reinterpret_cast<T*>(&data._stack), std::forward<Args>(args)...);
				}

				static vtable* get_vtable()
				{
					static vtable _vtable = {
						type,
						_delete,
						copy,
						copy_use_resource,
						move,
						move_use_resource,
					};
					return &_vtable;
				}
			};

			template<class T>
			struct dynamic_vtable
			{
				static const std::type_info& type() noexcept
				{
					return typeid(T);
				}
				static void copy(const Data & from, Data & to)
				{
					to._resource = from._resource;
					polymorphic_allocator<> alloc{ to._resource };
					to._dynamic = alloc.new_object<T>(*reinterpret_cast<const T*>(from._dynamic));
				}
				static void copy_use_resource(const Data & from, Data & to)
				{
					polymorphic_allocator<> alloc{ to._resource };
					to._dynamic = alloc.new_object<T>(*reinterpret_cast<const T*>(from._dynamic));
				}

				static void move(Data & from, Data & to) noexcept
				{
					to._resource = from._resource;
					to._dynamic = from._dynamic;
					from._dynamic = nullptr;
				}

				static void move_use_resource(Data & from, Data & to) noexcept
				{
					if(*from._resource == *to._resource)
					{
						to._dynamic = from._dynamic;
						from._dynamic = nullptr;
					}
					else
					{
						polymorphic_allocator<> alloc{ to._resource };

						to._dynamic = alloc.new_object<T>(std::move(*reinterpret_cast<T*>(from._dynamic)));
						_delete(from);
					}
				}

				static void _delete(Data & data) noexcept
				{
					//if(data._dynamic)
					{
						pmr::polymorphic_allocator<> alloc(data._resource);
						alloc.delete_object(reinterpret_cast<T*>(data._dynamic));
						data._dynamic = nullptr;
					}

				}

				template<class...Args>
				static void create(Data & data, Args&&...args)
				{
					pmr::polymorphic_allocator<> alloc(data._resource);
					data._dynamic = alloc.new_object<T>(std::forward<Args>(args)...);
				}

				static vtable* get_vtable()
				{
					static vtable _vtable = {
						type,
						_delete,
						copy,
						copy_use_resource,
						move,
						move_use_resource,
					};
					return &_vtable;
				}
			};


			template<class T>
			using VTable = std::conditional_t< can_fit<T>::value, stack_vtable<T>, dynamic_vtable<T> >;

		public:
			using allocator_type = pmr::polymorphic_allocator<>;

			any() noexcept {}

			any(none_t) noexcept {}

			any(const any& other)
				:pvtable(other.pvtable)
			{
				if(other.has_value())
				{
					other.pvtable->_copy(other._data, _data);
				}
			}

			any(any&& other) noexcept
				:pvtable(other.pvtable)
				, _data(other._data._resource)
			{
				if(other.has_value())
				{
					other.pvtable->_move_use_resource(other._data, _data);
					other.pvtable = nullptr;
				}
			}

			template<typename T, typename = std::enable_if_t<!std::is_same< std::decay_t<T>, any >::value> >
			any(T&& value)
				:pvtable(VTable<std::decay_t<T>>::get_vtable())
			{
				VTable<std::decay_t<T>>::create(_data, std::forward<T>(value));
			}

			template<typename T, class... Args, typename = std::enable_if_t<!std::is_same< std::decay_t<T>, any >::value> >
			explicit any(::cpp::in_place_type_t<T>, Args&&... args)
				:pvtable(VTable<T>::get_vtable())
			{
				VTable<T>::create(_data, std::forward<Args>(args)...);
			}

			template<typename T, class U, class... Args,
				typename = std::enable_if_t<!std::is_same< std::decay_t<T>, any >::value>,
				typename = std::enable_if_t < std::is_constructible<T, std::initializer_list<U>&, Args&&...>::value >>
				explicit any(::cpp::in_place_type_t<T>, std::initializer_list<U> ilist, Args&&... args)
				:pvtable(VTable<T>::get_vtable())
			{
				VTable<T>::create(_data, ilist, std::forward<Args>(args)...);
			}

			//////////////////////////////////////////////////////////////////////////

			template<class _Alloc>
			any(std::allocator_arg_t, _Alloc const& a)
				:_data(get_memory_resource(a))
			{

			}

			template<class _Alloc>
			any(std::allocator_arg_t, _Alloc const& a, const any& other)
				: pvtable(other.pvtable)
				, _data(get_memory_resource(a))
			{
				if(other.has_value())
				{
					other.pvtable->_copy_use_resource(other._data, _data);
				}
			}

			template<class _Alloc>
			any(std::allocator_arg_t, _Alloc const& a, any&& other)
				: pvtable(other.pvtable)
				, _data(get_memory_resource(a))
			{
				if(other.has_value())
				{
					other.pvtable->_move_use_resource(other._data, _data);
					other.pvtable = nullptr;
				}
			}

			template<typename T, class _Alloc, typename = std::enable_if_t<!std::is_same< std::decay_t<T>, any >::value> >
			any(std::allocator_arg_t, _Alloc const& a, T&& value)
				:pvtable(VTable<std::decay_t<T>>::get_vtable())
				, _data(get_memory_resource(a))
			{
				VTable<std::decay_t<T>>::create(_data, std::forward<T>(value));
			}


			template<typename T, class _Alloc, class... Args, typename = std::enable_if_t<!std::is_same< std::decay_t<T>, any >::value > >
			any(std::allocator_arg_t, _Alloc const& a, cpp::in_place_type_t<T> inplace, Args&&... args)
				:pvtable(VTable<T>::get_vtable())
				, _data(get_memory_resource(a))
			{
				VTable<T>::create(_data, std::forward<Args>(args)...);
			}

			template<typename T, class _Alloc, class U, class... Args,
				typename = std::enable_if_t<!std::is_same< std::decay_t<T>, any >::value>,
				typename = std::enable_if_t < std::is_constructible<T, std::initializer_list<U>&, Args&&...>::value >>
				any(std::allocator_arg_t, _Alloc const& a, cpp::in_place_type_t<T>, std::initializer_list<U> ilist, Args&&... args)
				:pvtable(VTable<T>::get_vtable())
				, _data(get_memory_resource(a))
			{
				VTable<T>::create(_data, ilist, std::forward<Args>(args)...);
			}

			~any()
			{
				reset();
			}

			any& operator=(none_t) noexcept
			{
				reset();
				return *this;
			}

			any& operator=(const any& rhs)
			{
				if(this == &rhs)
				{
					return *this;
				}
				any(rhs).swap(*this);
				return *this;
			}
			any& operator=(any&& rhs)
			{
				if(this == &rhs)
				{
					return *this;
				}
				any(std::move(rhs)).swap(*this);
				return *this;
			}

			template<typename ValueType, typename = std::enable_if_t<!std::is_same< std::decay_t<ValueType>, any >::value>>
			any& operator=(ValueType&& value)
			{
				any(std::allocator_arg, _data._resource, std::forward<ValueType>(value)).swap(*this);
				return *this;
			}

			void swap(any& other) noexcept
			{
				if(!has_value() && !other.has_value())
					return;

				if(has_value() && other.has_value())
				{
					if(this == &other)
					{
						return;
					}

					any tmp;
					tmp.pvtable = pvtable;
					pvtable->_move(_data, tmp._data);
					//pvtable->_delete(_data);

					pvtable = other.pvtable;
					pvtable->_move_use_resource(other._data, _data);
					//other.pvtable->_delete(other._data);

					other.pvtable = tmp.pvtable;
					other.pvtable->_move_use_resource(tmp._data, other._data);
					//tmp.pvtable->_delete(tmp._data);
					tmp.pvtable = nullptr;

				}
				else
				{
					any* hasValue = has_value() ? this : &other;
					any* noValue = !has_value() ? this : &other;

					noValue->pvtable = hasValue->pvtable;
					hasValue->pvtable->_move_use_resource(hasValue->_data, noValue->_data);
					//hasValue->pvtable->_delete(hasValue->_data);
					hasValue->pvtable = nullptr;
				}
			}


			void reset() noexcept
			{
				if(pvtable)
				{
					pvtable->_delete(_data);
					pvtable = nullptr;
				}
			}

			bool has_value() const noexcept
			{
				return !!pvtable;
			}

			const type_info& type() const
			{
				return pvtable ? pvtable->_type() : typeid(void);
			}

			template<typename T>
			void assign(T&& value)
			{
				reset();
				VTable<std::decay_t<T>>::create(_data, std::forward<T>(value));
				pvtable = VTable<std::decay_t<T>>::get_vtable();
			}

			template<typename T, class A>
			void assign(T&& value, A const& a)
			{
				reset();
				_data._resource = get_memory_resource(a);
				VTable<std::decay_t<T>>::create(_data, std::forward<T>(value));
				pvtable = VTable<std::decay_t<T>>::get_vtable();
			}


			template<typename T, class... Args>
			void emplace(Args&&... args)
			{
				reset();
				VTable<T>::create(_data, std::forward<Args>(args)...);
				pvtable = VTable<T>::get_vtable();
			}

			template<typename T, class U, class... Args>
			void emplace(std::initializer_list<U> ilist, Args&&... args)
			{
				reset();
				VTable<T>::create(_data, ilist, std::forward<Args>(args)...);
				pvtable = VTable<T>::get_vtable();
			}

			//
			template< class T, class A, class ... Args >
			void allocate_emplace(A const & a, Args && ... args)
			{
				reset();
				_data._resource = get_memory_resource(a);
				VTable<T>::create(_data, std::forward<Args>(args)...);
				pvtable = VTable<T>::get_vtable();
			}

			template<typename T, class A, class U, class... Args>
			void allocate_emplace(A const & a, std::initializer_list<U> ilist, Args&&... args)
			{
				reset();
				_data._resource = get_memory_resource(a);
				VTable<T>::create(_data, ilist, std::forward<Args>(args)...);
				pvtable = VTable<T>::get_vtable();
			}


			/**
			*
			**/
			template<class T>
			T value()
			{
				using unref = std::remove_reference_t < T >;

				using ref = std::conditional_t < std::is_reference<T>::value, T, std::add_lvalue_reference_t<unref> >;

				auto pv = target<unref>();
				if(!pv)
				{
					throw bad_any_cast();
				}

				return  static_cast<ref>(*pv);
			}

			template<class T>
			typename __any::_AddConst<T>::type  value() const
			{
				using unref = std::remove_reference_t < T >;

				using ref = std::conditional_t < std::is_reference<T>::value,
					typename __any::_AddConst<T>::type,
					std::add_lvalue_reference_t<const unref> >;

				auto pv = target<unref>();
				if(!pv)
				{
					throw bad_any_cast();
				}

				return  static_cast<ref>(*pv);
			}

		private:

			template<class T> struct _AlwaysFalse{ static const bool value = false; };
			template<class Alloc, class = std::enable_if_t <!std::is_convertible_v<Alloc, pmr::polymorphic_allocator<> > > >
			auto get_memory_resource(Alloc const& alloc)
			{
				static_assert(_AlwaysFalse<Alloc>::value, "resource_adaptor disallowed");
				return get_default_resource();
			}

			template<class U>
			auto get_memory_resource(pmr::polymorphic_allocator<U> const& alloc)
			{
				return alloc.resource();
			}

			auto get_memory_resource(pmr::memory_resource* r)
			{
				return r;
			}

			template< class T >
			T* target()
			{
				if(pvtable && pvtable->_type() == typeid(T))
				{
					if(can_fit< std::remove_const_t< T > >::value)
					{
						return std::addressof(reinterpret_cast<T&>(_data._stack));
					}
					else
					{
						return std::addressof(*static_cast<T*>(_data._dynamic));
					}
				}
				return nullptr;
			}

			template< class T >
			const T* target() const
			{
				if(pvtable && pvtable->_type() == typeid(T))
				{
					if(can_fit< std::remove_const_t< T > >::value)
					{
						return std::addressof(reinterpret_cast<const T&>(_data._stack));
					}
					else
					{
						return std::addressof(*static_cast<const T*>(_data._dynamic));
					}
				}
				return nullptr;
			}

			template<class ValueType>
			friend	const ValueType* any_cast(const any* operand);

			template<class ValueType>
			friend ValueType* any_cast(any* operand);
		};

		inline void swap(any& lhs, any& rhs) noexcept
		{
			lhs.swap(rhs);
		}

		template<int..., class T>
		any make_any(T&& value)
		{
			return{ std::forward<T>(value) };
		}

		template <class T, class ...Args>
		any make_any(Args&& ...args)
		{
			return any{ in_place<T>, std::forward<Args>(args)... };
		}

		template <class T, class U, class ...Args>
		any make_any(std::initializer_list<U> il, Args&& ...args)
		{
			return any{ in_place<T>, il, std::forward<Args>(args)... };
		}


		template<class ValueType>
		ValueType* any_cast(any* operand)
		{
			return  operand ? operand->target<ValueType>() : nullptr;
		}

		template<class ValueType>
		const ValueType* any_cast(const any* operand)
		{
			return  operand ? operand->target<ValueType>() : nullptr;
		}


		template<class ValueType>
		typename __any::_AddConst<ValueType>::type any_cast(const any& operand)
		{
			using unref = std::remove_reference_t < ValueType >;

			using ref = std::conditional_t < std::is_reference<ValueType>::value,
				typename __any::_AddConst<ValueType>::type,
				std::add_lvalue_reference_t<const unref> >;

			auto pv = any_cast<unref>(&operand);
			if(!pv)
			{
				throw bad_any_cast();
			}

			return static_cast<ref>(*pv);
		}

		template<class ValueType>
		ValueType any_cast(any& operand)
		{
			using unref = std::remove_reference_t < ValueType >;

			using ref = std::conditional_t < std::is_reference<ValueType>::value, ValueType, std::add_lvalue_reference_t<unref> >;

			auto pv = any_cast<unref>(&operand);
			if(!pv)
			{
				throw bad_any_cast();
			}

			return  static_cast<ref>(*pv);
		}

		template<class ValueType, class = std::enable_if_t< std::is_rvalue_reference<ValueType&&>::value || std::is_const< std::remove_reference_t< ValueType > >::value  > >
		ValueType any_cast(any&& operand)
		{
			return any_cast<ValueType&&>(operand);
		}

	}

	template <>
	struct nullable_traits<pmr::any> {
		static constexpr none_t none() { return none_t{}; }
	};
}
#endif

#include "config/config_end.h"